/*-
 * Copyright (c) 2007 Microsoft
 * All rights reserved.
 */

#include "StdAfx.h"
#include "MPICore.h"
#include "Comm.h"
#include "MPIException.h"
#include "TypeMapper.h"

using namespace Microsoft::ComputeCluster::MpiNet;

///<summary>
///Reduces a value on all processes to a single value
///</summary>
///<param name="root">root process id</param>
///<param name="input">input data, root don't need provide this</param>
///<param name="output">output data, only root provide this</param>
///<param name="op">operation</param>
generic<class t> void Comm::Reduce(int root, t input, [Out] t% output, int op)
{
    if (t::typeid->IsPrimitive)
    {
        t result;
        int mpitype = TypeMapper::Get(t::typeid);

        int ret = MPI_Reduce(&input, &result, 1, mpitype, op, root, handle);
        if (ret != MPI_SUCCESS)
            throw gcnew MPIException(ret);
        output = result;
        return;
    }

    throw gcnew System::NotImplementedException();
}

///<summary>
///Reduces values on all processes to a single value
///</summary>
///<param name="root">root process id</param>
///<param name="input">input data, root don't need provide this</param>
///<param name="output">output data, only root provide this</param>
///<param name="op">operation</param>
generic<typename t> void Comm::Reduce(int root, array<t>^ input, array<t>^ output, int op)
{
    if (t::typeid->IsPrimitive)
    {
        int mpitype = TypeMapper::Get(t::typeid);
        pin_ptr<t> inp = &input[0];
        pin_ptr<t> outp = &output[0];
        int ret = MPI_Reduce(inp, outp, input->Length, mpitype, (int)op, root, handle);
        if (ret != MPI_SUCCESS)
            throw gcnew MPIException(ret);
        return;
    }

    throw gcnew System::NotImplementedException();
}

///<summary>
///Reduces values on all processes to a single value and then return the results to all processors
///</summary>
///<param name="input">input data, root don't need provide this</param>
///<param name="output">output data, only root provide this</param>
///<param name="op">operation</param>
generic<typename t> void Comm::AllReduce(array<t>^ input, array<t>^ output, int op)
{
    if (t::typeid->IsPrimitive)
    {
        int mpitype = TypeMapper::Get(t::typeid);
        pin_ptr<t> inp = &input[0];
        pin_ptr<t> outp = &output[0];

        int ret = MPI_Allreduce(inp, outp, input->Length, mpitype, (int)op, handle);
        if (ret != MPI_SUCCESS)
            throw gcnew MPIException(ret);
        return;
    }

    throw gcnew System::NotImplementedException();
}
